
#include <stdlib.h>     // Header file for malloc/free.
#include <stdio.h>      // Header file for standard file i/o.
#include <GL/glut.h>    // Header File For The GLUT Library 
#include <iostream>
#include <math.h>

#include "Timer.h"
#include "MathMisc.h"

#include "MegaMan.h"
#include "Level.h"
#include "Camera.h"

int window;

float mX = 0, mY = 40, mZ = 0;
float cR = 320, cY = 80, cA = 270, cF = -10;

MegaMan *Mega = new MegaMan();
Camera MainCamera;
Level TestLevel;

Timer fps;

static float last_time;

using namespace std;

bool LockFramesPerSecond(int framerate)
{
	float current_time = fps.get_ticks() * 0.001f;
	if ( (current_time - last_time) > (1.0f / framerate))
	{
		last_time = current_time;
		return true;
	}
	return false;
}

bool InitGL (int Width, int Height )
{

    glEnable(GL_TEXTURE_2D);							// Enable Texture Mapping
    glShadeModel(GL_SMOOTH);							// Enables Smooth Color Shading
    glClearColor(0.0f, 0.0f, 0.0f, 0.5f);				// Clear The Background Color To Black 
    glClearDepth(1.0);									// Enables Clearing Of The Depth Buffer
    glEnable(GL_DEPTH_TEST);							// Enables Depth Testing
    glDepthFunc(GL_LEQUAL);								// The Type Of Depth Test To Do
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);	//Really nice perspective calculations
	
	// Setup Alpha
	glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE);

	// Setup 
	if ( SDL_Init(SDL_INIT_TIMER) )
		return false;
	memset( KeyDown, false, sizeof( KeyDown ) );
	memset( KeyDownSpecial, false, sizeof( KeyDownSpecial ) );

	// Setup Perspective
	glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,16000.0f);	// Calculate The Aspect Ratio Of The Window
    glMatrixMode(GL_MODELVIEW);

	Mega->setMega(Position(0, 40, 0));
	MainCamera.setCamera(Position(320, 40, -10, 270), Mega);

	fps.start();
	last_time = fps.get_ticks();

	if (!TestLevel.LoadTextures())
		return false;
	return true;
}

void GLDisplay(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// Begin the View
	glLoadIdentity();

	// Camera - Working on a boom. Always follows MegaMan!
	// Must be done FIRST. Edits ModelView Matrix.
	//gluLookAt(mX+cR*sin(toRadian(cA)), cY+mY, mZ+cR*cos(toRadian(cA)), mX, cF, mZ, 0, 1, 0);
	MainCamera.Update();

	glPushMatrix();

	// Draw ground
	TestLevel.Update();

	// Lets draw MegaManCube
	Mega->Update();

	glutSwapBuffers();

}

void GLIdle(void)
{
	if(LockFramesPerSecond(60))
		glutPostRedisplay();
}

void GLResize(int Width, int Height)
{
    if (Height==0)				// Prevent A Divide By Zero If The Window Is Too Small
	Height=1;

    glViewport(0, 0, Width, Height);		// Reset The Current Viewport And Perspective Transformation

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,16000.0f);
    glMatrixMode(GL_MODELVIEW);
}

/* The function called whenever a key is pressed. */
void HandleInputDown(unsigned char key, int x, int y) 
{
    /* If escape is pressed, kill everything. */
    switch(key)
    { 
		// Close Program
		case 27: // Escape
			glutDestroyWindow(window); 
			exit(0);
			break;
    }
	
	KeyDown[key] = true;

	Mega->HandleInput();
	MainCamera.HandleInput();
}

void HandleInputUp(unsigned char key, int x, int y) 
{
	KeyDown[key] = false;

	Mega->HandleInput();
	MainCamera.HandleInput();
}

// Special key function.
void SpecialInput(int key, int x, int y)
{
	switch (key)
	{
		case GLUT_KEY_UP:
			KeyDownSpecial[0] = true;
			break;
		case GLUT_KEY_DOWN:
			KeyDownSpecial[1] = true;
			break;
		case GLUT_KEY_LEFT:
			KeyDownSpecial[2] = true;
			break;
		case GLUT_KEY_RIGHT:
			KeyDownSpecial[3] = true;
			break;
		case GLUT_KEY_F1:
			glutFullScreen();
			break;
		case GLUT_KEY_F2:
			glutReshapeWindow (1024, 768);
			break;
	}
	Mega->HandleInput();
	MainCamera.HandleInput();
}

void SpecialInputUp(int key, int x, int y)
{
	switch (key)
	{
		case GLUT_KEY_UP:
			KeyDownSpecial[0] = false;
			break;
		case GLUT_KEY_DOWN:
			KeyDownSpecial[1] = false;
			break;
		case GLUT_KEY_LEFT:
			KeyDownSpecial[2] = false;
			break;
		case GLUT_KEY_RIGHT:
			KeyDownSpecial[3] = false;
			break;
		case GLUT_KEY_F1:
			glutFullScreen();
			break;
		case GLUT_KEY_F2:
			glutReshapeWindow (1024, 768);
			break;
	}
	Mega->HandleInput();
	MainCamera.HandleInput();
}

int main(int argc, char **argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);

	glutInitWindowSize(1024, 768);
	glutInitWindowPosition(0,0);

	window = glutCreateWindow("MegaManGL - Land Demo");
	
	glutDisplayFunc(&GLDisplay);
	glutIdleFunc(&GLIdle);
	glutReshapeFunc(&GLResize);
	glutSetKeyRepeat(GLUT_KEY_REPEAT_OFF);
	glutKeyboardFunc(&HandleInputDown);
	glutKeyboardUpFunc(&HandleInputUp);
	glutSpecialFunc(&SpecialInput);
	glutSpecialUpFunc(&SpecialInputUp);


	if( InitGL(1024, 768) )
		glutMainLoop();

	cin >> mX;
	return 1;
}